﻿namespace Vibstudio.X4NET.IO.Path
{
    #region Namespaces

    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;

    #endregion

    public class FilePath
    {
        #region Ctor(s)

        public FilePath(string path)
        {
            Path = path;

            if (!FilePathInternal.HasParentDir(Path))
            {
                throw new ArgumentNullException(Path, @"The file path has no parent directory.");
            }
        }

        #endregion

        #region Factory

        public static FilePath Create(string path)
        {
            return new FilePath(path);
        }

        #endregion

        #region Public Properties

        public bool Exists
        {
            get { return File.Exists(Path); }
        }

        public string FileExtension
        {
            get { return FilePathInternal.GetExtension(Path); }
        }

        public string FileExtensionWithoutDot
        {
            get { return FileExtension.Substring(1); }
        }

        public FileInfo FileInfo
        {
            get
            {
                if (!Exists)
                {
                    throw new FileNotFoundException(Path);
                }
                return new FileInfo(Path);
            }
        }

        public string ZipFileName
        {
            get
            {
                return string.Format("{0}.zip", FileNameWithoutExtension);
            }
        }

        public string FileName
        {
            get { return FilePathInternal.GetLastName(Path); }
        }

        public string BackupFileName
        {
            get
            {
                string date = DateTime.Now.ToString("ddMMyy", CultureInfo.InvariantCulture);
                string time = DateTime.Now.ToString("HHmmss", CultureInfo.InvariantCulture);
                return string.Format("{0}{1}{2}-{3}{4}",
                                     FileNameWithoutExtension,
                                     FileName.Split('_').Length > 1
                                         ? "__"
                                         : "_",
                                     date,
                                     time,
                                     FileExtension);
            }
        }

        public string FileNameWithoutExtension
        {
            get
            {
                string fileName = FileName;
                string extension = FileExtension;
                if (string.IsNullOrEmpty(extension))
                {
                    return fileName;
                }
                return fileName.Substring(0, fileName.Length - extension.Length);
            }
        }

        public string ZipPath
        {
            get
            {
                string zipFileName = string.Format("{0}.zip", FileNameWithoutExtension);
                return System.IO.Path.Combine(PathWithoutFile, zipFileName);
            }
        }

        public string Path { get; private set; }
        
        public string PathWithoutFile
        {
            get
            {
                string temp = Path.Substring(0, Path.IndexOf(FileName, StringComparison.Ordinal) - 1);
                return temp;
            }
        }

        #endregion

        #region Overrides

        public static bool operator ==(FilePath a, FilePath b)
        {
            if (ReferenceEquals(a, b)) return true;

            if (((object)a == null) || ((object)b == null)) return false;

            return a.Path == b.Path;
        }

        public static bool operator !=(FilePath x, FilePath y)
        {
            return !(x == y);
        }

        protected bool Equals(FilePath other)
        {
            return string.Equals(Path, other.Path);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != GetType())
            {
                return false;
            }
            return Equals((FilePath)obj);
        }

        public override int GetHashCode()
        {
            return (Path != null ? Path.GetHashCode() : 0);
        }

        #endregion

        internal class FilePathInternal
        {
            #region Static Fields

            private static readonly char DIR_SEPARATOR_CHAR = System.IO.Path.DirectorySeparatorChar;

            private static readonly string DIR_SEPARATOR_STRING = System.IO.Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture);

            #endregion

            #region Methods

            internal static string GetExtension(string path)
            {
                string fileName = GetLastName(path);
                int index = fileName.LastIndexOf('.');
                if (index == -1)
                {
                    return string.Empty;
                }
                if (index == fileName.Length - 1)
                {
                    return string.Empty;
                }
                return fileName.Substring(index, fileName.Length - index);
            }

            internal static string GetLastName(string path)
            {
                if (!HasParentDir(path))
                {
                    return string.Empty;
                }
                int index = path.LastIndexOf(DIR_SEPARATOR_CHAR);
                Debug.Assert(index != path.Length - 1);
                return path.Substring(index + 1, path.Length - index - 1);
            }

            internal static bool HasParentDir(string path)
            {
                return path.Contains(DIR_SEPARATOR_STRING);
            }

            #endregion
        }
    }
}
